/*
 * PacketEditor.cpp
 *
 *  Created on: 21.04.2011
 *      Author: mifodix
 */

#include "PacketEditor.hpp"

PacketEditor::PacketEditor()
{
	//значения полей по умолчанию
	this->htype=1;
	this->hlen=6;
	this->hops=0;
	memset(&this->sname, 0, 64);
	memset(&this->file, 0, 128);
}

PacketEditor::PacketEditor(const char *packet, size_t size)
{
	SetPacket(packet, size);
}

char *PacketEditor::GetChaddr() const
{
	char *res=new char[sizeof(this->chaddr)];
	memmove(res, &this->chaddr, sizeof(this->chaddr));
	return res;
}

uint32_t PacketEditor::GetCiaddr() const
{
    return ciaddr;
}

char *PacketEditor::GetFile() const
{
	char *res=new char[sizeof(this->file)];
	memmove(res, &this->file, sizeof(this->file));
	return res;
}

uint16_t PacketEditor::GetFlags() const
{
    return flags;
}

uint32_t PacketEditor::GetGiaddr() const
{
    return giaddr;
}

unsigned char PacketEditor::GetHlen() const
{
    return hlen;
}

unsigned char PacketEditor::GetHops() const
{
    return hops;
}

unsigned char PacketEditor::GetHtype() const
{
    return htype;
}

unsigned char PacketEditor::GetOp() const
{
    return op;
}

std::list<Option> PacketEditor::GetOptions() const
{
	return options;
}

size_t PacketEditor::GetPacket(char *&packet)
{
    //генерация пакета
	size_t size=0;
	std::list<Option>::iterator it;
	for (it=options.begin(); it!=options.end(); ++it)
	{
		size+=it->GetSize();
	}
	size+=(MAIN_SIZE+MAGIC_COOKIE_SIZE+1);//выделяем 1 байт для опции END
	packet=new char[size];
	char *cur=packet;
	*cur=op;
	cur++;
	*cur=htype;
	cur++;
	*cur=hlen;
	cur++;
	*cur=hops;
	cur++;

	uint16_t temp16;
	uint32_t temp32;

	temp32=NetUtils::HostOrd2NetOrd(xid);
	memmove(cur, &temp32, sizeof(temp32));
	cur+=sizeof(temp32);

	temp16=NetUtils::HostOrd2NetOrd(secs);
	memmove(cur, &temp16, sizeof(temp16));
	cur+=sizeof(temp16);

	temp16=NetUtils::HostOrd2NetOrd(flags);
	memmove(cur, &temp16, sizeof(temp16));
	cur+=sizeof(temp16);

	temp32=NetUtils::HostOrd2NetOrd(ciaddr);
	memmove(cur, &temp32, sizeof(temp32));
	cur+=sizeof(temp32);

	temp32=NetUtils::HostOrd2NetOrd(yiaddr);
	memmove(cur, &temp32, sizeof(temp32));
	cur+=sizeof(temp32);

	temp32=NetUtils::HostOrd2NetOrd(siaddr);
	memmove(cur, &temp32, sizeof(temp32));
	cur+=sizeof(temp32);

	temp32=NetUtils::HostOrd2NetOrd(giaddr);
	memmove(cur, &temp32, sizeof(temp32));
	cur+=sizeof(temp32);

	memmove(cur, &chaddr, sizeof(chaddr));
	cur+=sizeof(chaddr);

	memmove(cur, &sname, sizeof(sname));
	cur+=sizeof(sname);

	memmove(cur, &file, sizeof(file));
	cur+=sizeof(file);

	if (!options.empty())
	{
		*cur=MAGIC_COOKIE_1;
		cur++;
		*cur=MAGIC_COOKIE_2;
		cur++;
		*cur=MAGIC_COOKIE_3;
		cur++;
		*cur=MAGIC_COOKIE_4;
		cur++;
		std::list<Option>::iterator it;
		unsigned char l;
		for (it=options.begin(); it!=options.end(); ++it)
		{
			*cur=it->GetCode();
			cur++;
			*cur=it->GetLen();
			cur++;
			l=it->GetLen();
			memmove(cur, it->GetData(), l);
			cur+=l;
		}
		*cur=END_OPTION;
	}
	//выравнивание?
	return size;
}

uint16_t PacketEditor::GetSecs() const
{
    return secs;
}

uint32_t PacketEditor::GetSiaddr() const
{
    return siaddr;
}

char *PacketEditor::GetSname() const
{
	char *res=new char[sizeof(this->sname)];
	memmove(res, &this->sname, sizeof(this->sname));
	return res;
}

uint32_t PacketEditor::GetXid() const
{
    return xid;
}

uint32_t PacketEditor::GetYiaddr() const
{
    return yiaddr;
}

void PacketEditor::SetChaddr(const char *chaddr)
{
	memmove(&this->chaddr, chaddr, sizeof(this->chaddr));
}

void PacketEditor::SetCiaddr(uint32_t ciaddr)
{
    this->ciaddr = ciaddr;
}

void PacketEditor::SetFile(const char *file)
{
	memmove(&this->file, file, sizeof(this->file));
}

void PacketEditor::SetFlags(uint16_t flags)
{
    this->flags = flags;
}

void PacketEditor::SetGiaddr(uint32_t giaddr)
{
    this->giaddr = giaddr;
}

void PacketEditor::SetHlen(unsigned char hlen)
{
    this->hlen = hlen;
}

void PacketEditor::SetHops(unsigned char hops)
{
    this->hops = hops;
}

void PacketEditor::SetHtype(unsigned char htype)
{
    this->htype = htype;
}

void PacketEditor::SetOp(unsigned char op)
{
    this->op = op;
}

void PacketEditor::SetOptions(std::list <Option> options)
{
	this->options=options;
}

void PacketEditor::SetPacket(const char *packet, size_t size)
{
    //разбор полей
    const char * cur=packet;
    op=*cur++;
    htype=*cur++;
    hlen=*cur++;
    hops=*cur++;
    memmove(&xid, cur, sizeof(xid));
    cur+=sizeof(xid);
    xid=NetUtils::NetOrd2HostOrd(xid);

    memmove(&secs, cur, sizeof(secs));
    cur+=sizeof(secs);
    secs=NetUtils::NetOrd2HostOrd(secs);

    memmove(&flags, cur, sizeof(flags));
    cur+=sizeof(flags);
    flags=NetUtils::NetOrd2HostOrd(flags);

    memmove(&ciaddr, cur, sizeof(ciaddr));
    cur+=sizeof(ciaddr);
    ciaddr=NetUtils::NetOrd2HostOrd(ciaddr);

    memmove(&yiaddr, cur, sizeof(yiaddr));
    cur+=sizeof(yiaddr);
    yiaddr=NetUtils::NetOrd2HostOrd(yiaddr);

    memmove(&siaddr, cur, sizeof(siaddr));
    cur+=sizeof(siaddr);
    siaddr=NetUtils::NetOrd2HostOrd(siaddr);

    memmove(&giaddr, cur, sizeof(giaddr));
    cur+=sizeof(giaddr);
    giaddr=NetUtils::NetOrd2HostOrd(giaddr);

    memmove(&chaddr, cur, sizeof(chaddr));
    cur+=sizeof(chaddr);

    memmove(&sname, cur, sizeof(sname));
    cur+=sizeof(sname);

    memmove(&file, cur, sizeof(file));

    if (size>MAIN_SIZE)//разбор опций
    {
    	cur+=(sizeof(file)+MAGIC_COOKIE_SIZE);//не  забываем про magic cookie
    	unsigned char code, len;
    	char *data;
    	while(true)
    	{
    		code=*cur++;
    		if (code==END_OPTION) break;
    		len=*cur++;
    		data=new char[len];
    		memmove(data, cur, len);
    		AddOption(code, len, data);
    		delete[] data;
    		cur+=len;
    	}
    }
}

void PacketEditor::SetSecs(uint16_t secs)
{
    this->secs = secs;
}

void PacketEditor::SetSiaddr(uint32_t siaddr)
{
    this->siaddr = siaddr;
}

void PacketEditor::SetSname(const char *sname)
{
	memmove(&this->sname, sname, strlen(sname)>sizeof(this->sname) ? sizeof(this->sname) : strlen(sname));
}

void PacketEditor::SetXid(uint32_t xid)
{
    this->xid = xid;
}

void PacketEditor::SetYiaddr(uint32_t yiaddr)
{
    this->yiaddr = yiaddr;
}

bool PacketEditor::AddOption(unsigned char code, unsigned char len, const char *data)
{
	if (FindOption(code)==NULL)
	{
		Option newOp(code, len, data);
		options.push_back(newOp);
		return true;
	}
	return false;
}

PacketEditor::~PacketEditor()
{
}

Option* PacketEditor::FindOption(unsigned char code)
{
	for (std::list<Option>::iterator it=options.begin(); it!=options.end(); ++it)
	{
		if (it->GetCode()==code)
		{
			return &(*it);
		}
	}
	return NULL;
}

PacketEditor & PacketEditor::operator =(const PacketEditor & ob)
{
	if (this!=&ob)
	{
		this->op=ob.op;
		this->htype=ob.htype;
		this->hlen=ob.hlen;
		this->hops=ob.hops;
		this->xid=ob.xid;
		this->secs=ob.secs;
		this->flags=ob.flags;
		this->ciaddr=ob.ciaddr;
		this->giaddr=ob.giaddr;
		this->siaddr=ob.siaddr;
		this->yiaddr=ob.yiaddr;
		this->options=ob.options;
		memmove(&this->chaddr, &ob.chaddr, sizeof(chaddr));
		memmove(&this->sname, &ob.sname, sizeof(sname));
		memmove(&this->file, &ob.file, sizeof(file));
	}
	return *this;
}

PacketEditor::PacketEditor(const PacketEditor & copy): op(copy.op), htype(copy.htype), hlen(copy.hlen), hops(copy.hops), xid(copy.xid), secs(copy.secs), flags(copy.flags), ciaddr(copy.ciaddr), yiaddr(copy.yiaddr), siaddr(copy.siaddr), giaddr(copy.giaddr), options(copy.options)
{
	memmove(&this->chaddr, &copy.chaddr, sizeof(chaddr));
	memmove(&this->sname, &copy.sname, sizeof(sname));
	memmove(&this->file, &copy.file, sizeof(file));
}

bool PacketEditor::RemoveOption(unsigned char code)
{
	Option *found=FindOption(code);
	if (found!=NULL)
	{
		options.remove(*found);
		return true;
	}
	return false;
}

void PacketEditor::ClearOptions()
{
	options.clear();
}




